package br.com.minhasfinancas.fw.manager;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.persistence.NoResultException;
import javax.persistence.Query;

import br.com.minhasfinancas.fw.interfaces.CrudManager;

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class GenericCrudManager<E, ID> extends AbstractManager<E> implements
		CrudManager<E, ID> {

	private static final long serialVersionUID = 1L;

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public void alterar(E entity) {
		getEntityManager().merge(entity);
		getEntityManager().flush();
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public void excluir(ID id) {
		getEntityManager().remove(this.obter(id));
		getEntityManager().flush();
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
	public void inserir(E entity){
		getEntityManager().persist(entity);
		getEntityManager().flush();
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
	public E obter(ID id) {
		Object findId = id;
		if (id instanceof String) {
			findId = Long.valueOf((String) id);
		}
		final E find = getEntityManager().find(this.getEntityClass(), findId);
		return find;
	}

	@SuppressWarnings("unchecked")
	@Override
	@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
	public List<E> obterTodos() {
		final Query query = this.getEntityManager().createQuery("from " + getEntityClass().getCanonicalName());
		return query.getResultList();
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
	public List<E> findByNamedQuery(String namedQueryName) {
		return findByNamedQuery(namedQueryName, new HashMap<String, Object>());
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
	public List<E> findByNamedQuery(String namedQueryName,
			Map<String, Object> parameters) {
		return this.findWithNamedQueryPaginated(namedQueryName, parameters, 0,
				0);
	}

	@SuppressWarnings("unchecked")
	@Override
	@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
	public E findOneByNamedQuery(String namedQueryName, ID id) {
		final Query query = this.getEntityManager().createNamedQuery(
				namedQueryName);
		query.setParameter("id", id);
		E result = null;
		try {
			result = (E) query.getSingleResult();
		} catch (NoResultException exception) {
			return null;
		}
		return result;
	}

	@SuppressWarnings("unchecked")
	@Override
	@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
	public E findOneByNamedQuery(String namedQueryName,
			Map<String, Object> parameters) {
		final Query query = this.getEntityManager().createNamedQuery(
				namedQueryName);
		for (final Map.Entry<String, Object> entry : parameters.entrySet()) {
			query.setParameter(entry.getKey(), entry.getValue());
		}
		E result = null;
		try {
			result = (E) query.getSingleResult();
		} catch (NoResultException exception) {
			return null;
		}
		return result;
	}

	@Override
	@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
	public List<E> findWithNamedQueryPaginated(String namedQueryName,
			int firstResult, int resultLimit) {
		// TODO Auto-generated method stub
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
	public List<E> findWithNamedQueryPaginated(String namedQueryName,
			Map<String, Object> parameters, int firstResult, int resultLimit) {

		final Query query = getEntityManager().createNamedQuery(namedQueryName);
		if (firstResult > 0) {
			query.setFirstResult(firstResult);
		}
		if (resultLimit > 0) {
			query.setMaxResults(resultLimit);
		}
		for (final Map.Entry<String, Object> entry : parameters.entrySet()) {
			query.setParameter(entry.getKey(), entry.getValue());
		}
		return query.getResultList();
	}

}
